/*
	Filename	:	dibsection32.cpp
	Author(s)	:	Ray E. Bornert II
				:	Gregory R. Hnat
	Date		:	2001-SEP-18
	Copyright	:	(c) 2001 RealTimeGaming

	History		:

	Comments	:	32bit DibSection code
*/

//////////////
// INCLUDES //
//////////////
//#include "stdafx.h"

#include "dibsection.h"
#include "lib.h"
#include "bitmap.h"


#if USE32BITDIB
#define BITSPERPIXEL (32)
#define BYTESPERPIXEL (BITSPERPIXEL/8)


#if USEJPEG
#include "jpeglib.h"
#endif

#if USEPNG
#include "png.h"
#endif

#if USEJPEG
int LoadJPEG (const char* pfileName, DibSection* pds);
#endif

#if USEPNG
int LoadPNG(const char *file_name, DibSection* pds);
#endif

#define BIGASSUINT 4294967295

void AlphaLine (UCHAR* pDest, UCHAR* pSrc, int width, int byteCount);


void DibSection::Init(void)
{
	m_hbmp = NULL;
	memset (&m_ds, 0, sizeof(DIBSECTION));
}

DibSection::DibSection ()
{
	Init();
}

DibSection::~DibSection ()
{
	Clear ();
}

void DibSection::Clear (void)
{
	if (m_hbmp)
		DeleteObject (m_hbmp);
	m_hbmp = NULL;
	memset (&m_ds, 0, sizeof(DIBSECTION));
}


int DibSection::Resize (USHORT depth, long width, long height)
{
	int iResult;

	HDC hdc;
	BITMAPINFO bmi;
	BITMAPINFOHEADER* pbmih;

	//Remove the old HBITMAP - if any.
	Clear ();

	//Initialize our struct to 0's and then set the fields we need.
	memset (&bmi, 0, sizeof(BITMAPINFO));

	//set the convenience pointer
	pbmih = &bmi.bmiHeader;

	//plug all the values
	pbmih->biBitCount		= depth;
	pbmih->biClrImportant	= 0;
	pbmih->biClrUsed		= 0;
	pbmih->biCompression	= BI_RGB;
	pbmih->biHeight			= height;
	pbmih->biPlanes			= 1;
	pbmih->biSize			= sizeof (BITMAPINFOHEADER);
	pbmih->biSizeImage		= 0;
	pbmih->biWidth			= width;

	//Create the actual DibSection and get a copy of the DIBSECTION struct
	hdc = GetDC (NULL);
	m_hbmp = CreateDIBSection
	(
		hdc,
		&bmi,
		DIB_RGB_COLORS,
		NULL,
		NULL,
		0
	);

	ReleaseDC (NULL, hdc);

	//did it fail?
	if (m_hbmp == NULL)
		return (-1);

	iResult = GetObject(m_hbmp, sizeof(DIBSECTION), &m_ds);
	if (iResult < 0)
		return (-2);

	//all is well
	return (0);
}

int ConvertScanline24to32
(
	BYTE*	pDst,
	BYTE*	pSrc,
	int		nPixels
)
{
	if (pDst == NULL)
		return (-1);

	if (pSrc == NULL)
		return (-2);

	const int srcStride=3;
	const int dstStride=BYTESPERPIXEL;

	BYTE*	_pSrc=pSrc;
	BYTE*	_pDst=pDst;

	for (int i=0; i<nPixels; i++)
	{
		_pDst[0] = _pSrc[0];
		_pDst[1] = _pSrc[1];
		_pDst[2] = _pSrc[2];
		_pDst[3] = 0xff;

		_pSrc += srcStride;
		_pDst += dstStride;
	}

	//all is well
	return (0);
}

int ConvertTo32BitDib( HBITMAP* pHbm )
{
	int iResult;

	DIBSECTION ds;

	// We got the image now get the information
	iResult = GetObject(*pHbm, sizeof(DIBSECTION), &ds);
	if (iResult < 0)
		return (-1);

	if (ds.dsBm.bmBitsPixel == BITSPERPIXEL)
		return (1);

	if (ds.dsBm.bmBitsPixel != 24)
		return (-2);

	HDC hdc;
	BITMAPINFO bmi;
	BITMAPINFOHEADER* pbmih;

	const int width = ds.dsBm.bmWidth;
	const int height= ds.dsBm.bmHeight;

	//Initialize our struct to 0's and then set the fields we need.
	memset (&bmi, 0, sizeof(BITMAPINFO));

	//set the convenience pointer
	pbmih = &bmi.bmiHeader;

	//plug all the values
	pbmih->biBitCount		= BITSPERPIXEL;
	pbmih->biClrImportant	= 0;
	pbmih->biClrUsed		= 0;
	pbmih->biCompression	= BI_RGB;
	pbmih->biHeight			= height;
	pbmih->biPlanes			= 1;
	pbmih->biSize			= sizeof (BITMAPINFOHEADER);
	pbmih->biSizeImage		= 0;
	pbmih->biWidth			= width;

	//Create the actual DibSection and get a copy of the DIBSECTION struct
	hdc = GetDC (NULL);
	HBITMAP hbm;
	hbm = CreateDIBSection
	(
		hdc,
		&bmi,
		DIB_RGB_COLORS,
		NULL,
		NULL,
		0
	);

	ReleaseDC (NULL, hdc);

	//did it fail?
	if (hbm == NULL)
		return (-3);

	DIBSECTION _ds;
	// We got the image now get the information
	iResult = GetObject(hbm, sizeof(DIBSECTION), &_ds);
	if (iResult < 0)
		return (-4);

	BYTE* pDst = (BYTE*) _ds.dsBm.bmBits;
	BYTE* pSrc = (BYTE*)  ds.dsBm.bmBits;
	int dstStride = _ds.dsBm.bmWidthBytes;
	int srcStride =  ds.dsBm.bmWidthBytes;

	//gotta dword align the stride
	dstStride+=3; dstStride&=(~3);
	srcStride+=3; srcStride&=(~3);

	for (int j=0; j<height; j++)
	{
		iResult = ConvertScanline24to32( pDst, pSrc, width );
		pDst += dstStride;
		pSrc += srcStride;
	}

	DeleteObject( *pHbm );
	*pHbm = hbm;

	pDst -= dstStride;
	unsigned long transColor = *((unsigned long*)pDst);

	////////////////////////////////////////////////////
	pDst = (BYTE*) _ds.dsBm.bmBits;
	for (int k=0; k<height; k++)
	{
		for (int i=0; i<width;  i++)
		{
			unsigned long* _pDst = (unsigned long*)pDst;
			unsigned long color = _pDst[i];
			if (color == transColor)
			{
//				color &= 0x00ffffff;
				color = 0;
				_pDst[i] = color;
			}
		}
		pDst += dstStride;
	}
	////////////////////////////////////////////////////

	//all is well
	return (0);
}

int DibSection::LoadBMP( LPCSTR pfileName )
{
	int iResult;

	// Load the BMP from file
	m_hbmp = (HBITMAP)LoadImage
	(
		NULL,
		pfileName,
		IMAGE_BITMAP,
		0,
		0,
		LR_CREATEDIBSECTION|LR_DEFAULTSIZE|LR_LOADFROMFILE
	);
	if (m_hbmp == NULL)
		return (-1);

	iResult = ConvertTo32BitDib( &m_hbmp );
	if (iResult < 0)
		return (-2);

	// We got the image now get the information
	iResult = GetObject(m_hbmp, sizeof(DIBSECTION), &m_ds);
	if (iResult < 0)
		return (-3);

	//all is well
	return (0);
}

int DibSection::Load (LPCSTR pfileName)
{
	int iResult;
	FILE* pfp;
	char buf[64];

	// Remove the old HBITMAP - if any.
	Clear ();

	pfp = fopen (pfileName, "rb");
	if (pfp == NULL)
		return (-9);

	fread (buf, 64, 1, pfp);
	fclose (pfp);

#if USEJPEG
	if (memcmp (buf+6, "JFIF", 4) == 0)
	{
		iResult = LoadJPEG (pfileName, this);
		if (iResult < 0)
			return (-1);
	}
#endif

#if USEPNG
	if (memcmp (buf+1, "PNG", 3) == 0)
	{
		iResult = LoadPNG (pfileName, this);
		if (iResult < 0)
			return (-2);

	}
#endif

	//we use BMP's by default
	if (memcmp (buf, "BM", 2) == 0)
	{
		iResult = LoadBMP(pfileName);
		if (iResult < 0)
			return (-3);
	}

	//all is well
	return (0);
}

int DibSection::Load (FILE* pfp)
{
	// To do
	return -1;
}

int DibSection::Paint (HDC hdc, long x, long y)
{
	int iResult;
	HDC memdc;

	//gotta have an object
	if (m_hbmp == NULL)
		return (-1);

	// Only paint if we have a valid DibSection
	memdc = CreateCompatibleDC (NULL);
	SelectObject (memdc, m_hbmp);
	iResult = BitBlt
	(
		hdc,
		0,
		0,
		m_ds.dsBm.bmWidth,
		m_ds.dsBm.bmHeight,
		memdc,
		x,
		y,
		SRCCOPY
	);
	DeleteDC (memdc);

	if (iResult == 0)
		return (-2);

	//all is well
	return (0);
}


// NOTE:  This assumes DibSection and HDC are same size!!!
int DibSection::PaintRect (HDC hdc, int x, int y, RECT* pr)
{
/*
	int iResult;

	iResult = Paint( hdc, 0,0 );
	if (iResult < 0)
		return (-1);
*/
	int iResult;
	HDC memdc;

	//gotta have an object
	if (m_hbmp == NULL)
		return (-1);

	// Only paint if we have a valid DibSection
	memdc = CreateCompatibleDC (NULL);
	SelectObject (memdc, m_hbmp);
	iResult = BitBlt
	(
		hdc,
		x,
		y,
		pr->right-pr->left,
		pr->bottom-pr->top,
		memdc,
		pr->left,
		pr->top,
		SRCCOPY
	);
	DeleteDC (memdc);

	if (iResult == 0)
		return (-2);


	//all is well
	return (0);
}

long DibSection::Width (void)
{
	return m_ds.dsBm.bmWidth;
}

long DibSection::Height (void)
{
	return m_ds.dsBm.bmHeight;
}

short DibSection::BitCount (void)
{
	return m_ds.dsBm.bmBitsPixel;
}

BYTE* DibSection::GetBits (long y, long x)
{
	BYTE* pimg = NULL;
	long size;

	if (m_hbmp)
	{
		size = ((Height()-1) - y) * ByteWidth ();
		if (x)
			size += (BitCount () / 8) * x;
		pimg = (BYTE*)m_ds.dsBm.bmBits + size;
	}
	return pimg;
}

BYTE* DibSection::GetBitsAddress(void)
{
	//RETURN MEMORY ADDRESS OF RGB VALUES
	//PLEASE NOTE THAT THIS ADDRESS IS NOT THE 0,0 PIXEL
	//DIBSECTIONS ARE BOTTOM UP
	//THE PIXEL AT THIS ADDRESS IS ACTUALL x=0,y=height-1
	BYTE* pImg = (BYTE*)m_ds.dsBm.bmBits;
	return pImg;
}

HBITMAP DibSection::GetBitmap (void)
{
	return m_hbmp;
}

long DibSection::ByteWidth (void)
{
	long size, bc;

	// Get the width and bitcount for this image
	size = Width();
	bc = BitCount();

	// calculate the number of bytes a line will need
	switch (bc)
	{
	case 1:
	case 4:
		size *= 8/bc;
		break;
	case 8:
	case 16:
	case 24:
	case 32:
		size *= bc/8;
		break;

	}
	// Make sure the answer is DWORD aligned...
	return  (((size+3)>>2)<<2);
}


#ifdef _DEBUG
int DibSection::Test (HWND hwnd)
{
#ifdef _TESTING
	long val;
	RECT r;
	DibSection ds, dest;
	HDC hdc;

	val = ds.Width ();
	val = ds.Height ();
	val = ds.ByteWidth ();
	val = ds.BitCount ();

	ds.Load ("resources\\queen.bmp");
	val = dest.Resize (ds.BitCount(), ds.Width ()>>1, ds.Height ()>>1);
	val = ds.Width ();
	val = ds.Height ();
	val = ds.ByteWidth ();
	val = ds.BitCount ();


	SetRect (&r, 0, 0, dest.Width (), dest.Height ());
	val = DibSectionBlit (&dest, &ds, 0, 0, &r);
	hdc = GetDC (NULL);
	dest.Paint (hdc, 0, 0);
	ReleaseDC (NULL, hdc);


	hdc = CreateCompatibleDC (NULL);
	val = (long)SelectObject (hdc, ds.GetBitmap());
	SetRect (&r, 50, 50, 100, 100);
	FillRect(hdc, &r, (HBRUSH) (COLOR_WINDOW+1));
	SelectObject (hdc, (void*)val);
	DeleteDC (hdc);

	hdc = GetDC (NULL);
	ds.Paint (hdc, 0, 0);
	ReleaseDC (NULL, hdc);


	ds.Resize (ds.BitCount(), 200, 200);
	hdc = CreateCompatibleDC (NULL);
	val = (long)SelectObject (hdc, ds.GetBitmap());
	SetRect (&r, 0, 0, 200, 200);
	FillRect(hdc, &r, (HBRUSH) (COLOR_HIGHLIGHT));
	SelectObject (hdc, (void*)val);
	DeleteDC (hdc);

	hdc = GetDC (NULL);
	ds.Paint (hdc, 0, 0);
	ReleaseDC (NULL, hdc);
#endif

	return 0;
}
#endif

#if USEJPEG
int LoadJPEG (const char* pfileName, DibSection* pds)
{

	struct jpeg_decompress_struct cinfo;
	struct jpeg_error_mgr jerr;
	int row_stride;		/* physical row width in output buffer */
	BYTE* pdest;
	FILE* pfp;

	pfp = fopen (pfileName, "rb");
 	cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_decompress(&cinfo);
	jpeg_stdio_src(&cinfo, pfp);
	jpeg_read_header(&cinfo, TRUE);
	jpeg_start_decompress(&cinfo);

	pds->Resize (BITSPERPIXEL, cinfo.output_width, cinfo.output_height);
	row_stride = cinfo.output_width * cinfo.output_components;

	//TEMPORARY BUFFER
	BYTE* tempDest = new BYTE[ cinfo.output_width * 4 ];

	while (cinfo.output_scanline < cinfo.output_height)
	{
		// By changing the JPEG library we can have it produce BGR instead of RGB...
		// see jmorecfg.h
		pdest = pds->GetBits(cinfo.output_scanline/*-1*/);
		jpeg_read_scanlines(&cinfo, &tempDest, 1);

		int iResult = ConvertScanline24to32( pdest, tempDest, cinfo.output_width );
		if (iResult < 0)
			return (-1);
	}
	jpeg_finish_decompress(&cinfo);
	jpeg_destroy_decompress(&cinfo);
	fclose (pfp);

	delete []tempDest;

	return 0;
}
#endif


#if USEPNG
int LoadPNG(const char *file_name, DibSection* pds)
{
	png_structp png_ptr;
	png_infop info_ptr;
	unsigned int sig_read = 0;
	FILE *fp;

	if ((fp = fopen(file_name, "rb")) == NULL)
		return (-1);
	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (png_ptr == NULL)
	{
		fclose(fp);
		return (-2);
	}
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL)
	{
		fclose(fp);
		png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
		return (-3);
	}
	if (setjmp(png_jmpbuf(png_ptr)))
	{
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
		fclose(fp);
		return (-4);
	}
	png_init_io(png_ptr, fp);
	png_set_sig_bytes(png_ptr, sig_read);

	// png_read_png(png_ptr, info_ptr, 0/*png_transforms*/, NULL);
	// By passing in PNG_TRANSFORM_BGR, PNG will produce BGR instead of RGB...
//	png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_BGR|PNG_TRANSFORM_SWAP_ALPHA, NULL);
	png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_BGR, NULL);
//	png_read_png(png_ptr, info_ptr, NULL, NULL);
	pds->Resize (BITSPERPIXEL, info_ptr->width, info_ptr->height);
	for (int i=0; i<(int)info_ptr->height; ++i)
	{
//		unsigned long pixel[256];
//		memcpy (pixel, info_ptr->row_pointers[i], info_ptr->rowbytes);
//		memcpy (pds->GetBits (i), info_ptr->row_pointers[i], info_ptr->rowbytes );
		if (info_ptr->channels == 3) //24 bit png
		{
			int iResult = ConvertScanline24to32(pds->GetBits (i), info_ptr->row_pointers[i], info_ptr->width );
			if (iResult < 0)
				return (-1);
		}
		else
		if (info_ptr->channels == 4)
			memcpy (pds->GetBits (i), info_ptr->row_pointers[i], info_ptr->width*4 );
		else
			memcpy (pds->GetBits (i), info_ptr->row_pointers[i], info_ptr->rowbytes );


//		RGBToBGR (pds->GetBits (i), info_ptr->row_pointers[i], info_ptr->width);
	}
	png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
	fclose(fp);

	/* that's it */
	return (0);
}

#endif

int DibSection::Clip
(
	RECT *pSrc,
	RECT *pSrcSub,
	RECT *pDst,
	RECT *pDstSub
)
{
	//translation vector from src to dst
	int transx = pDstSub->left - pSrcSub->left;
	int transy = pDstSub->top - pSrcSub->top;

	//translate the src to dst space
	OffsetRect( pSrcSub, transx, transy );
	OffsetRect( pSrc, transx, transy );

	//gotta have equal src and dst rects
	if (!EqualRect( pSrcSub, pDstSub ))
		return (-1);

	//get the intersection of src dst and the sub
	IntersectRect( pDstSub, pDstSub, pDst );
	IntersectRect( pDstSub, pDstSub, pSrc );

	//is there nothing
	if (IsRectEmpty( pDstSub ))
		return (-2);

	//src sub and dst sub are equivalent
	*pSrcSub = *pDstSub;

	//translate the src back to src space
	OffsetRect( pSrcSub, -transx, -transy );
	OffsetRect( pSrc, -transx, -transy );

	//all is well
	return (0);
}

int DibSection::Clip2
(
	DibSection *pDsDest,
	int& nXOriginDest,   // x-coord of destination upper-left corner
	int& nYOriginDest,   // y-coord of destination upper-left corner
	int& nWidthDest,     // width of destination rectangle
	int& nHeightDest,    // height of destination rectangle
	DibSection *pDsSrc,
	int& nXOriginSrc,    // x-coord of source upper-left corner
	int& nYOriginSrc,    // y-coord of source upper-left corner
	int& nWidthSrc,      // width of source rectangle
	int& nHeightSrc     // height of source rectangle
)
{
	/////////////////////////////////////////////
	//this routine requires that the source and dest recangles be equal
	//and at least 1x1 pixel
	if (nWidthSrc != nWidthDest)
		return (-1);

	if (nHeightSrc != nHeightDest)
		return (-2);

	if (nWidthSrc < 1)
		return (-3);

	if (nHeightSrc < 1)
		return (-4);

	//ok so the source and dest rectangles are equal

	//is the destination hanging off the left edge
	if (nXOriginDest < 0)
	{
		//move srcx to the right
		nXOriginSrc -= nXOriginDest;
		//move dstx to the left edge
		nXOriginDest = 0;
	}

	if (nYOriginDest < 0)
	{
		//move srcy upward
		nYOriginSrc -= nYOriginDest;
		//move dsty to the bottom
		nYOriginDest = 0;
	}

	if (nXOriginSrc < 0)
	{
		//move dstx to the right
		nXOriginDest -= nXOriginSrc;
		//move srcx to the left edge
		nXOriginSrc = 0;
	}

	if (nYOriginSrc < 0)
	{
		//move dsty upward
		nYOriginDest -= nYOriginSrc;
		//move srcy to the bottom
		nYOriginSrc = 0;
	}

	//are the origins inside the pixel space
	int srcWidth = pDsSrc->Width();
	int srcHeight = pDsSrc->Height();
	if (nXOriginSrc >= srcWidth)
		return (-5);
	if (nYOriginSrc >= srcHeight)
		return (-6);

	int dstWidth = pDsDest->Width();
	int dstHeight = pDsDest->Height();
	if (nXOriginDest >= dstWidth)
		return (-7);
	if (nYOriginDest >= dstHeight)
		return (-8);

	//ok the origin for both source and dest is within the respective bitspace

	if ((nXOriginDest + nWidthDest) > dstWidth)
	{
		nWidthDest = nWidthSrc = (dstWidth - nXOriginDest);
	}

	if ((nYOriginDest + nHeightDest) > dstHeight)
	{
		nHeightDest = nHeightSrc = (dstHeight - nYOriginDest);
	}

	if ((nXOriginSrc + nWidthSrc) > srcWidth)
	{
		nWidthSrc = nWidthDest = (srcWidth - nXOriginSrc);
	}

	if ((nYOriginSrc + nHeightSrc) > srcHeight)
	{
		nHeightSrc = nHeightDest = (srcHeight - nYOriginSrc);
	}
	/////////////////////////////////////////////

	//all is well
	return (0);
}

int DibSection::TransparentBlt
(
	DibSection *pDsDest,
	int nXOriginDest,   // x-coord of destination upper-left corner
	int nYOriginDest,   // y-coord of destination upper-left corner
	int nWidthDest,     // width of destination rectangle
	int nHeightDest,    // height of destination rectangle
	DibSection *pDsSrc,
	int nXOriginSrc,    // x-coord of source upper-left corner
	int nYOriginSrc,    // y-coord of source upper-left corner
	int nWidthSrc,      // width of source rectangle
	int nHeightSrc,     // height of source rectangle
	UINT crTransparent  // color to make transparent
)
{
	int iResult;

#if 1

	RECT rDst,rSrc,rDstSub,rSrcSub;
	SetRect( &rDst, 0,0, pDsDest->Width(), pDsDest->Height() );
	SetRect( &rSrc, 0,0, pDsSrc->Width(), pDsSrc->Height() );
	SetRect( &rDstSub, nXOriginDest, nYOriginDest, nXOriginDest+nWidthDest, nYOriginDest+nHeightDest );
	SetRect( &rSrcSub, nXOriginSrc, nYOriginSrc, nXOriginSrc+nWidthSrc, nYOriginSrc+nHeightSrc );

	iResult = Clip( &rSrc, &rSrcSub, &rDst, &rDstSub );
	if (iResult < 0)
		return (1);

	BYTE *srcBits = pDsSrc->GetBits (rSrcSub.top, rSrcSub.left);
	BYTE *dstBits = pDsDest->GetBits (rDstSub.top, rDstSub.left);
	BYTE *pTcolor = (BYTE *)(&crTransparent);

	//what is the width and height of the rect we're supposed to blit
	int width = rSrcSub.right - rSrcSub.left;
	int height= rSrcSub.bottom - rSrcSub.top;

#else

	iResult = Clip2
	( 
		pDsDest,
		nXOriginDest,   // x-coord of destination upper-left corner
		nYOriginDest,   // y-coord of destination upper-left corner
		nWidthDest,     // width of destination rectangle
		nHeightDest,    // height of destination rectangle
		pDsSrc,
		nXOriginSrc,    // x-coord of source upper-left corner
		nYOriginSrc,    // y-coord of source upper-left corner
		nWidthSrc,      // width of source rectangle
		nHeightSrc      // height of source rectangle
	);

	BYTE *srcBits = pDsSrc->GetBits (nYOriginSrc, nXOriginSrc);
	BYTE *dstBits = pDsDest->GetBits (nYOriginDest,nXOriginDest);
	BYTE *pTcolor = (BYTE *)(&crTransparent);

	//what is the width and height of the rect we're supposed to blit
	int width = nWidthSrc;
	int height= nHeightSrc;

#endif

	//size of 1 pixel in bytes
	int hstepSrc=BYTESPERPIXEL;
	int hstepDst=BYTESPERPIXEL;

	//offset to next line (it's a bottom up situtation)
	int vstepSrc = -pDsSrc->ByteWidth() - (width*hstepSrc);
	int vstepDst = -pDsDest->ByteWidth() - (width*hstepDst);

	//each row
	for (int j=height; j; j--)
	{
		//each column
		for (int i=width; i; i--)
		{
			if (srcBits[3] == 0)
				goto skip;

			//copy the pixel
			*((long*)(dstBits)) = *((long*)(srcBits));

			skip:

			//move the column pointers
			srcBits += hstepSrc;
			dstBits += hstepDst;
		}

		//move the row pointers
		srcBits += vstepSrc;
		dstBits += vstepDst;
	}

	//all is well
	return (1);
}

int DibSection::TransparentAlphaBlt
(
	DibSection *pDsDest,
	int nXOriginDest,   // x-coord of destination upper-left corner
	int nYOriginDest,   // y-coord of destination upper-left corner
	int nWidthDest,     // width of destination rectangle
	int nHeightDest,    // height of destination rectangle
	DibSection *pDsSrc,
	int nXOriginSrc,    // x-coord of source upper-left corner
	int nYOriginSrc,    // y-coord of source upper-left corner
	int nWidthSrc,      // width of source rectangle
	int nHeightSrc,     // height of source rectangle
	UINT crTransparent  // color to make transparent
)
{
	int iResult;

#if 1

	RECT rDst,rSrc,rDstSub,rSrcSub;
	SetRect( &rDst, 0,0, pDsDest->Width(), pDsDest->Height() );
	SetRect( &rSrc, 0,0, pDsSrc->Width(), pDsSrc->Height() );
	SetRect( &rDstSub, nXOriginDest, nYOriginDest, nXOriginDest+nWidthDest, nYOriginDest+nHeightDest );
	SetRect( &rSrcSub, nXOriginSrc, nYOriginSrc, nXOriginSrc+nWidthSrc, nYOriginSrc+nHeightSrc );

	iResult = Clip( &rSrc, &rSrcSub, &rDst, &rDstSub );
	if (iResult < 0)
		return (1);

	BYTE *srcBits = pDsSrc->GetBits (rSrcSub.top, rSrcSub.left);
	BYTE *dstBits = pDsDest->GetBits (rDstSub.top, rDstSub.left);
	BYTE *pTcolor = (BYTE *)(&crTransparent);

	//what is the width and height of the rect we're supposed to blit
	int width = rSrcSub.right - rSrcSub.left;
	int height= rSrcSub.bottom - rSrcSub.top;

#else

	iResult = Clip2
	( 
		pDsDest,
		nXOriginDest,   // x-coord of destination upper-left corner
		nYOriginDest,   // y-coord of destination upper-left corner
		nWidthDest,     // width of destination rectangle
		nHeightDest,    // height of destination rectangle
		pDsSrc,
		nXOriginSrc,    // x-coord of source upper-left corner
		nYOriginSrc,    // y-coord of source upper-left corner
		nWidthSrc,      // width of source rectangle
		nHeightSrc      // height of source rectangle
	);

	BYTE *srcBits = pDsSrc->GetBits (nYOriginSrc, nXOriginSrc);
	BYTE *dstBits = pDsDest->GetBits (nYOriginDest,nXOriginDest);
	BYTE *pTcolor = (BYTE *)(&crTransparent);

	//what is the width and height of the rect we're supposed to blit
	int width = nWidthSrc;
	int height= nHeightSrc;

#endif

	//size of 1 pixel in bytes
	int hstepSrc=BYTESPERPIXEL;
	int hstepDst=BYTESPERPIXEL;

	//offset to next line (it's a bottom up situtation)
	int vstepSrc = -pDsSrc->ByteWidth() - (width*hstepSrc);
	int vstepDst = -pDsDest->ByteWidth() - (width*hstepDst);

	//each row
	for (int j=height; j; j--)
	{
		//each column
		for (int i=width; i; i--)
		{
			//is this pixel transparent
			if (srcBits[3] == 0)
				goto skip;

			//copy the pixel
			int k;

//			k = (dstBits[0] + srcBits[0]); if (k>255) k=255; dstBits[0] = (BYTE)k;
//			k = (dstBits[1] + srcBits[1]); if (k>255) k=255; dstBits[1] = (BYTE)k;
//			k = (dstBits[2] + srcBits[2]); if (k>255) k=255; dstBits[2] = (BYTE)k;
			k = (dstBits[0] + srcBits[0]) / 2; dstBits[0] = (BYTE)k;
			k = (dstBits[1] + srcBits[1]) / 2; dstBits[1] = (BYTE)k;
			k = (dstBits[2] + srcBits[2]) / 2; dstBits[2] = (BYTE)k;

			skip:

			//move the column pointers
			srcBits += hstepSrc;
			dstBits += hstepDst;
		}

		//move the row pointers
		srcBits += vstepSrc;
		dstBits += vstepDst;
	}

	//all is well
	return (1);
}

int CPUClock()
{
	_asm
	{
		cpuid
		rdtsc
	}
}

int DibSection::AlphaBlt
(
	DibSection *pDsDest,
	int nXOriginDest,   // x-coord of destination upper-left corner
	int nYOriginDest,   // y-coord of destination upper-left corner
	int nWidthDest,     // width of destination rectangle
	int nHeightDest,    // height of destination rectangle
	DibSection *pDsSrc,
	int nXOriginSrc,    // x-coord of source upper-left corner
	int nYOriginSrc,    // y-coord of source upper-left corner
	int nWidthSrc,      // width of source rectangle
	int nHeightSrc      // height of source rectangle
)
{
	int iResult;

#if 1

	RECT rDst,rSrc,rDstSub,rSrcSub;
	SetRect( &rDst, 0,0, pDsDest->Width(), pDsDest->Height() );
	SetRect( &rSrc, 0,0, pDsSrc->Width(), pDsSrc->Height() );
	SetRect( &rDstSub, nXOriginDest, nYOriginDest, nXOriginDest+nWidthDest, nYOriginDest+nHeightDest );
	SetRect( &rSrcSub, nXOriginSrc, nYOriginSrc, nXOriginSrc+nWidthSrc, nYOriginSrc+nHeightSrc );

	iResult = Clip( &rSrc, &rSrcSub, &rDst, &rDstSub );
	if (iResult < 0)
		return (1);

	BYTE *srcBits = pDsSrc->GetBits (rSrcSub.top, rSrcSub.left);
	BYTE *dstBits = pDsDest->GetBits (rDstSub.top, rDstSub.left);

	//what is the width and height of the rect we're supposed to blit
	int width = rSrcSub.right - rSrcSub.left;
	int height= rSrcSub.bottom - rSrcSub.top;

#else

	iResult = Clip2
	( 
		pDsDest,
		nXOriginDest,   // x-coord of destination upper-left corner
		nYOriginDest,   // y-coord of destination upper-left corner
		nWidthDest,     // width of destination rectangle
		nHeightDest,    // height of destination rectangle
		pDsSrc,
		nXOriginSrc,    // x-coord of source upper-left corner
		nYOriginSrc,    // y-coord of source upper-left corner
		nWidthSrc,      // width of source rectangle
		nHeightSrc      // height of source rectangle
	);

	BYTE *srcBits = pDsSrc->GetBits (nYOriginSrc, nXOriginSrc);
	BYTE *dstBits = pDsDest->GetBits (nYOriginDest,nXOriginDest);
	BYTE *pTcolor = (BYTE *)(&crTransparent);

	//what is the width and height of the rect we're supposed to blit
	int width = nWidthSrc;
	int height= nHeightSrc;

#endif

	//size of 1 pixel in bytes
	int hstepSrc=BYTESPERPIXEL;
	int hstepDst=BYTESPERPIXEL;

	//offset to next line (it's a bottom up situtation)
	int vstepSrc = -pDsSrc->ByteWidth() - (width*hstepSrc);
	int vstepDst = -pDsDest->ByteWidth() - (width*hstepDst);

#define ALPHATIME (0)
#if (1)
	__int64 t0=0;
	__int64 t1=0;
	t0 = CPUClock();
#endif

	//each row
	for (int j=height; j; j--)
	{
		//each column
		for (int i=width; i; i--)
		{
			//copy the pixel
			int alphaSrc = srcBits[3];

//			alphaSrc >>= 1;

			//COMPLETELY TRANSPARENT
			if (alphaSrc==0x00)
			{
				goto skip;
			}
			else
			//COMPLETELY OPAQUE
			if (alphaSrc==0xff)
			{
				//copy the pixel
				*((long*)(dstBits)) = *((long*)(srcBits));
				goto skip;
			}

			int alphaDst;
			alphaDst = 255 - alphaSrc;

			dstBits[0] = ((srcBits[0] * alphaSrc) + (dstBits[0] * alphaDst)) >> 8;
			dstBits[1] = ((srcBits[1] * alphaSrc) + (dstBits[1] * alphaDst)) >> 8;
			dstBits[2] = ((srcBits[2] * alphaSrc) + (dstBits[2] * alphaDst)) >> 8;
//			dstBits[0] = ((srcBits[0] * alphaSrc) + (dstBits[0] * (255-alphaSrc))) >> 8;
//			dstBits[1] = ((srcBits[1] * alphaSrc) + (dstBits[1] * (255-alphaSrc))) >> 8;
//			dstBits[2] = ((srcBits[2] * alphaSrc) + (dstBits[2] * (255-alphaSrc))) >> 8;

//			k = (dstBits[0] + srcBits[0]); if (k>255) k=255; dstBits[0] = (BYTE)k;
//			k = (dstBits[1] + srcBits[1]); if (k>255) k=255; dstBits[1] = (BYTE)k;
//			k = (dstBits[2] + srcBits[2]); if (k>255) k=255; dstBits[2] = (BYTE)k;
//			k = (dstBits[0] + srcBits[0]) / 2; dstBits[0] = (BYTE)k;
//			k = (dstBits[1] + srcBits[1]) / 2; dstBits[1] = (BYTE)k;
//			k = (dstBits[2] + srcBits[2]) / 2; dstBits[2] = (BYTE)k;
			/*
			_asm
			{
			mov		eax, [esi]		//source pixel
			mov		edx, [edi]		//dest pixel

			pxor	mm4, mm4		//make a zero reg

			shld	ebx,eax,8
			shld	ebx,eax,8
			shld	ebx,eax,8
			mov		ecx,ebx
			not		ecx

			movd	mm0, eax		//load the pixel bits into the mmx regs
			movd	mm1, ebx
			movd	mm2, ecx
			movd	mm3, edx

			punpcklbw	mm0, mm4	//unpack the bytes to words
			punpcklbw	mm1, mm4
			punpcklbw	mm2, mm4
			punpcklbw	mm3, mm4

			pmullw	mm0, mm1		//multiply the gun values by the alpha values
			pmullw	mm2, mm3

			paddusw	mm0, mm2		//add the source and dest

			psrlw	mm0, 8			//divide by 256

			packuswb mm0, mm0		//pack the words back into bytes

			movd	[edi], mm0		//write the pixel to the dest
			}
			*/
		skip:
			//move the column pointers
			srcBits += hstepSrc;
			dstBits += hstepDst;

			/*
			_asm
			{
				add esi,4
				add edi,4
			}
			*/
		}

		//move the row pointers
		srcBits += vstepSrc;
		dstBits += vstepDst;
	}

	_asm { emms }

#if (ALPHATIME)
	t1 = CPUClock();
	__int64 freq=500000000;
	double dt;
	dt = (double)t1 - (double)t0;
	double seconds = dt / freq;
	int pixels = width*height;
	char buf[256];
	sprintf(buf,"%d clocks\n%d pixels\nclocks/pixel %5.2f\n%9.5f seconds\n%9.2f Pixels/Second",(long)dt,pixels,dt/pixels,seconds,(double)pixels/seconds);
	MessageBox( NULL, buf, "Info", MB_OK );
#endif

	/*
	t0 = CPUClock();
	DWORD tick0 = GetTickCount();
	_asm
	{
		mov eax, 1000000000
rop:	dec eax
		jnz rop;
	}
	DWORD tick1 = GetTickCount();
	t1 = CPUClock();
	__int64 tt = t1-t0;
	sprintf(buf,"1000000000 rops / %d clocks\n%d Freq\n%d milliseconds",(long)tt,(long)freq,tick1-tick0);
	MessageBox( NULL, buf, "Info", MB_OK );
	*/

	//all is well
	return (1);
}

int DibSection::AlphaTransBlt
(
	DibSection *pDsDest,
	int nXOriginDest,   // x-coord of destination upper-left corner
	int nYOriginDest,   // y-coord of destination upper-left corner
	int nWidthDest,     // width of destination rectangle
	int nHeightDest,    // height of destination rectangle
	DibSection *pDsSrc,
	int nXOriginSrc,    // x-coord of source upper-left corner
	int nYOriginSrc,    // y-coord of source upper-left corner
	int nWidthSrc,      // width of source rectangle
	int nHeightSrc,     // height of source rectangle
	int trans
)
{
	int iResult;

#if 1

	RECT rDst,rSrc,rDstSub,rSrcSub;
	SetRect( &rDst, 0,0, pDsDest->Width(), pDsDest->Height() );
	SetRect( &rSrc, 0,0, pDsSrc->Width(), pDsSrc->Height() );
	SetRect( &rDstSub, nXOriginDest, nYOriginDest, nXOriginDest+nWidthDest, nYOriginDest+nHeightDest );
	SetRect( &rSrcSub, nXOriginSrc, nYOriginSrc, nXOriginSrc+nWidthSrc, nYOriginSrc+nHeightSrc );

	iResult = Clip( &rSrc, &rSrcSub, &rDst, &rDstSub );
	if (iResult < 0)
		return (1);

	BYTE *srcBits = pDsSrc->GetBits (rSrcSub.top, rSrcSub.left);
	BYTE *dstBits = pDsDest->GetBits (rDstSub.top, rDstSub.left);

	//what is the width and height of the rect we're supposed to blit
	int width = rSrcSub.right - rSrcSub.left;
	int height= rSrcSub.bottom - rSrcSub.top;

#else

	iResult = Clip2
	( 
		pDsDest,
		nXOriginDest,   // x-coord of destination upper-left corner
		nYOriginDest,   // y-coord of destination upper-left corner
		nWidthDest,     // width of destination rectangle
		nHeightDest,    // height of destination rectangle
		pDsSrc,
		nXOriginSrc,    // x-coord of source upper-left corner
		nYOriginSrc,    // y-coord of source upper-left corner
		nWidthSrc,      // width of source rectangle
		nHeightSrc      // height of source rectangle
	);

	BYTE *srcBits = pDsSrc->GetBits (nYOriginSrc, nXOriginSrc);
	BYTE *dstBits = pDsDest->GetBits (nYOriginDest,nXOriginDest);
	BYTE *pTcolor = (BYTE *)(&crTransparent);

	//what is the width and height of the rect we're supposed to blit
	int width = nWidthSrc;
	int height= nHeightSrc;

#endif

	//size of 1 pixel in bytes
	int hstepSrc=BYTESPERPIXEL;
	int hstepDst=BYTESPERPIXEL;

	//offset to next line (it's a bottom up situtation)
	int vstepSrc = -pDsSrc->ByteWidth() - (width*hstepSrc);
	int vstepDst = -pDsDest->ByteWidth() - (width*hstepDst);

#define ALPHATIME (0)
#if (1)
	__int64 t0=0;
	__int64 t1=0;
	t0 = CPUClock();
#endif

	//each row
	for (int j=height; j; j--)
	{
		//each column
		for (int i=width; i; i--)
		{
			//copy the pixel
			int alphaSrc = srcBits[3];

			alphaSrc >>= trans;

			//COMPLETELY TRANSPARENT
			if (alphaSrc==0x00)
			{
				goto skip;
			}
			else
			//COMPLETELY OPAQUE
			if (alphaSrc==0xff)
			{
				//copy the pixel
				*((long*)(dstBits)) = *((long*)(srcBits));
				goto skip;
			}

			int alphaDst;
			alphaDst = 255 - alphaSrc;

			dstBits[0] = ((srcBits[0] * alphaSrc) + (dstBits[0] * alphaDst)) >> 8;
			dstBits[1] = ((srcBits[1] * alphaSrc) + (dstBits[1] * alphaDst)) >> 8;
			dstBits[2] = ((srcBits[2] * alphaSrc) + (dstBits[2] * alphaDst)) >> 8;
//			dstBits[0] = ((srcBits[0] * alphaSrc) + (dstBits[0] * (255-alphaSrc))) >> 8;
//			dstBits[1] = ((srcBits[1] * alphaSrc) + (dstBits[1] * (255-alphaSrc))) >> 8;
//			dstBits[2] = ((srcBits[2] * alphaSrc) + (dstBits[2] * (255-alphaSrc))) >> 8;

//			k = (dstBits[0] + srcBits[0]); if (k>255) k=255; dstBits[0] = (BYTE)k;
//			k = (dstBits[1] + srcBits[1]); if (k>255) k=255; dstBits[1] = (BYTE)k;
//			k = (dstBits[2] + srcBits[2]); if (k>255) k=255; dstBits[2] = (BYTE)k;
//			k = (dstBits[0] + srcBits[0]) / 2; dstBits[0] = (BYTE)k;
//			k = (dstBits[1] + srcBits[1]) / 2; dstBits[1] = (BYTE)k;
//			k = (dstBits[2] + srcBits[2]) / 2; dstBits[2] = (BYTE)k;
			/*
			_asm
			{
			mov		eax, [esi]		//source pixel
			mov		edx, [edi]		//dest pixel

			pxor	mm4, mm4		//make a zero reg

			shld	ebx,eax,8
			shld	ebx,eax,8
			shld	ebx,eax,8
			mov		ecx,ebx
			not		ecx

			movd	mm0, eax		//load the pixel bits into the mmx regs
			movd	mm1, ebx
			movd	mm2, ecx
			movd	mm3, edx

			punpcklbw	mm0, mm4	//unpack the bytes to words
			punpcklbw	mm1, mm4
			punpcklbw	mm2, mm4
			punpcklbw	mm3, mm4

			pmullw	mm0, mm1		//multiply the gun values by the alpha values
			pmullw	mm2, mm3

			paddusw	mm0, mm2		//add the source and dest

			psrlw	mm0, 8			//divide by 256

			packuswb mm0, mm0		//pack the words back into bytes

			movd	[edi], mm0		//write the pixel to the dest
			}
			*/
		skip:
			//move the column pointers
			srcBits += hstepSrc;
			dstBits += hstepDst;

			/*
			_asm
			{
				add esi,4
				add edi,4
			}
			*/
		}

		//move the row pointers
		srcBits += vstepSrc;
		dstBits += vstepDst;
	}

	_asm { emms }

#if (ALPHATIME)
	t1 = CPUClock();
	__int64 freq=500000000;
	double dt;
	dt = (double)t1 - (double)t0;
	double seconds = dt / freq;
	int pixels = width*height;
	char buf[256];
	sprintf(buf,"%d clocks\n%d pixels\nclocks/pixel %5.2f\n%9.5f seconds\n%9.2f Pixels/Second",(long)dt,pixels,dt/pixels,seconds,(double)pixels/seconds);
	MessageBox( NULL, buf, "Info", MB_OK );
#endif

	/*
	t0 = CPUClock();
	DWORD tick0 = GetTickCount();
	_asm
	{
		mov eax, 1000000000
rop:	dec eax
		jnz rop;
	}
	DWORD tick1 = GetTickCount();
	t1 = CPUClock();
	__int64 tt = t1-t0;
	sprintf(buf,"1000000000 rops / %d clocks\n%d Freq\n%d milliseconds",(long)tt,(long)freq,tick1-tick0);
	MessageBox( NULL, buf, "Info", MB_OK );
	*/

	//all is well
	return (1);
}

int DibSection::LoLiteRect( RECT *pRect, int level )
{
	RECT rDst,rDstSub;
	SetRect( &rDst, 0,0, Width(), Height() );
	rDstSub = *pRect;

	IntersectRect( &rDstSub, &rDstSub, &rDst );

	if (IsRectEmpty( &rDstSub ))
		return (1);

	BYTE *dstBits = GetBits( rDstSub.top, rDstSub.left );

	//what is the width and height of the rect we're supposed to blit
	int width = rDstSub.right - rDstSub.left;
	int height= rDstSub.bottom - rDstSub.top;

	//size of 1 pixel in bytes
	int hstepDst=BYTESPERPIXEL;

	//offset to next line (it's a bottom up situtation)
	int vstepDst = -ByteWidth() - (width*hstepDst);

	if (level > 8)
		level = 8;

	//each row
	for (int j=height; j; j--)
	{
		//each column
		for (int i=width; i; i--)
		{
			//guns down
			dstBits[0] >>= level;
			dstBits[1] >>= level;
			dstBits[2] >>= level;

			//move the column pointers
			dstBits += hstepDst;
		}

		//move the row pointers
		dstBits += vstepDst;
	}

	//all is well
	return (1);
}

int DibSection::HiLiteRect( RECT *pRect, int level )
{
	RECT rDst,rDstSub;
	SetRect( &rDst, 0,0, Width(), Height() );
	rDstSub = *pRect;

	IntersectRect( &rDstSub, &rDstSub, &rDst );

	if (IsRectEmpty( &rDstSub ))
		return (1);

	BYTE *dstBits = GetBits( rDstSub.top, rDstSub.left );

	//what is the width and height of the rect we're supposed to blit
	int width = rDstSub.right - rDstSub.left;
	int height= rDstSub.bottom - rDstSub.top;

	//size of 1 pixel in bytes
	int hstepDst=BYTESPERPIXEL;

	//offset to next line (it's a bottom up situtation)
	int vstepDst = -ByteWidth() - (width*hstepDst);

	if (level > 8)
		level = 8;

	//each row
	for (int j=height; j; j--)
	{
		//each column
		for (int i=width; i; i--)
		{
			int k;

			//guns up
			k=dstBits[0]; k<<=level; if (k>255) k=255; dstBits[0]=k;
			k=dstBits[1]; k<<=level; if (k>255) k=255; dstBits[1]=k;
			k=dstBits[2]; k<<=level; if (k>255) k=255; dstBits[2]=k;

			//move the column pointers
			dstBits += hstepDst;
		}

		//move the row pointers
		dstBits += vstepDst;
	}

	//all is well
	return (1);
}

int DibSection::AlphaRect( RECT *pRect, double level )
{
	RECT rDst,rDstSub;
	SetRect( &rDst, 0,0, Width(), Height() );
	rDstSub = *pRect;

	IntersectRect( &rDstSub, &rDstSub, &rDst );

	if (IsRectEmpty( &rDstSub ))
		return (1);

	BYTE *dstBits = GetBits( rDstSub.top, rDstSub.left );

	//what is the width and height of the rect we're supposed to blit
	int width = rDstSub.right - rDstSub.left;
	int height= rDstSub.bottom - rDstSub.top;

	//size of 1 pixel in bytes
	int hstepDst=BYTESPERPIXEL;

	//offset to next line (it's a bottom up situtation)
	int vstepDst = -ByteWidth() - (width*hstepDst);

	if (level < 0)
		level = 0;

	//each row
	for (int j=height; j; j--)
	{
		//each column
		for (int i=width; i; i--)
		{
			double k;

			//guns up
			k=dstBits[0]; k*=level; if (k>255) k=255; dstBits[0]=(BYTE)k;
			k=dstBits[1]; k*=level; if (k>255) k=255; dstBits[1]=(BYTE)k;
			k=dstBits[2]; k*=level; if (k>255) k=255; dstBits[2]=(BYTE)k;

			//move the column pointers
			dstBits += hstepDst;
		}

		//move the row pointers
		dstBits += vstepDst;
	}

	//all is well
	return (1);
}

int DibSection::AlphaFill( RECT *pRect, COLORREF color )
{
	RECT rDst,rDstSub;
	SetRect( &rDst, 0,0, Width(), Height() );
	rDstSub = *pRect;

	color = ReverseOrder(color);

	IntersectRect( &rDstSub, &rDstSub, &rDst );

	if (IsRectEmpty( &rDstSub ))
		return (1);

	BYTE *dstBits = GetBits( rDstSub.top, rDstSub.left );

	//what is the width and height of the rect we're supposed to blit
	int width = rDstSub.right - rDstSub.left;
	int height= rDstSub.bottom - rDstSub.top;

	//size of 1 pixel in bytes
	int hstepDst=BYTESPERPIXEL;

	//offset to next line (it's a bottom up situtation)
	int vstepDst = -ByteWidth() - (width*hstepDst);

	BYTE *srcBits = (BYTE *)(&color);

	//each row
	for (int j=height; j; j--)
	{
		//each column
		for (int i=width; i; i--)
		{
			double k;

			//guns up
			k = (dstBits[0] + srcBits[0]) / 2; dstBits[0] = (BYTE)k;
			k = (dstBits[1] + srcBits[1]) / 2; dstBits[1] = (BYTE)k;
			k = (dstBits[2] + srcBits[2]) / 2; dstBits[2] = (BYTE)k;

			//move the column pointers
			dstBits += hstepDst;
		}

		//move the row pointers
		dstBits += vstepDst;
	}

	//all is well
	return (1);
}

int DibSection::Compliment( RECT *pRect )
{
	RECT rDst,rDstSub;
	SetRect( &rDst, 0,0, Width(), Height() );
	rDstSub = *pRect;

	IntersectRect( &rDstSub, &rDstSub, &rDst );

	if (IsRectEmpty( &rDstSub ))
		return (1);

	BYTE *dstBits = GetBits( rDstSub.top, rDstSub.left );

	//what is the width and height of the rect we're supposed to blit
	int width = rDstSub.right - rDstSub.left;
	int height= rDstSub.bottom - rDstSub.top;

	//size of 1 pixel in bytes
	int hstepDst=BYTESPERPIXEL;

	//offset to next line (it's a bottom up situtation)
	int vstepDst = -ByteWidth() - (width*hstepDst);

	//each row
	for (int j=height; j; j--)
	{
		//each column
		for (int i=width; i; i--)
		{			
			unsigned long* pC = (unsigned long*)dstBits;
			*pC = ~*pC;

			//move the column pointers
			dstBits += hstepDst;
		}

		//move the row pointers
		dstBits += vstepDst;
	}

	//all is well
	return (1);
}

int DibSection::AlphaFrame( RECT *pDest, RECT* pSrc, COLORREF color )
{
	//normalize the color
//	color = ReverseOrder(color);

	RECT rDst,rDstSub;

	//trivial rejection test
	IntersectRect( &rDst, pDest, pSrc );
	if (IsRectEmpty( &rDst ))
		return (1);

	//now bust the src frame into the 4 edge rectangles
	RECT rT,rB,rL,rR;
	SetRect(&rT,pSrc->left   ,pSrc->top     ,pSrc->right  ,pSrc->top+1 );
	SetRect(&rB,pSrc->left   ,pSrc->bottom-1,pSrc->right  ,pSrc->bottom);
	SetRect(&rL,pSrc->left   ,pSrc->top     ,pSrc->left+1 ,pSrc->bottom);
	SetRect(&rR,pSrc->right-1,pSrc->top     ,pSrc->right  ,pSrc->bottom);

	IntersectRect(&rDstSub,&rDst,&rT);
	if (IsRectEmpty( &rDstSub ) == 0)
		AlphaFill( &rDstSub, color );

	IntersectRect(&rDstSub,&rDst,&rB);
	if (IsRectEmpty( &rDstSub ) == 0)
		AlphaFill( &rDstSub, color );

	IntersectRect(&rDstSub,&rDst,&rL);
	if (IsRectEmpty( &rDstSub ) == 0)
		AlphaFill( &rDstSub, color );

	IntersectRect(&rDstSub,&rDst,&rR);
	if (IsRectEmpty( &rDstSub ) == 0)
		AlphaFill( &rDstSub, color );

	//all is well
	return (1);
}

// Do Alpha on one line, either rows or columns
void AlphaLine (UCHAR* pDest, UCHAR* pSrc, int width, int byteCount)
{
	for (int i=width; i; i--)
	{
		double k;

		k = (pDest[0] + pSrc[0]) / 2; pDest[0] = (BYTE)k;
		k = (pDest[1] + pSrc[1]) / 2; pDest[1] = (BYTE)k;
		k = (pDest[2] + pSrc[2]) / 2; pDest[2] = (BYTE)k;
		pDest += byteCount;
	}
}

int DibSection::SolidFillRect( RECT *pRect, COLORREF color )
{
	RECT rDst,rDstSub;
	SetRect( &rDst, 0,0, Width(), Height() );
	rDstSub = *pRect;
	color = ReverseOrder(color);

	IntersectRect( &rDstSub, &rDstSub, &rDst );

	if (IsRectEmpty( &rDstSub ))
		return (1);

	BYTE *dstBits = GetBits( rDstSub.top, rDstSub.left );

	//what is the width and height of the rect we're supposed to blit
	int width = rDstSub.right - rDstSub.left;
	int height= rDstSub.bottom - rDstSub.top;

	//size of 1 pixel in bytes
	int hstepDst=BYTESPERPIXEL;

	//offset to next line (it's a bottom up situtation)
	int vstepDst = -ByteWidth() - (width*hstepDst);

	BYTE *srcBits = (BYTE *)(&color);

	//each row
	for (int j=height; j; j--)
	{
		//each column
		for (int i=width; i; i--)
		{
			//Fill the line
			dstBits[0] = srcBits[0];
			dstBits[1] = srcBits[1];
			dstBits[2] = srcBits[2];

			//move the column pointers
			dstBits += hstepDst;
		}

		//move the row pointers
		dstBits += vstepDst;
	}

	//all is well
	return (1);
}

int DibSection::GetTransparentColor( COLORREF *pColor )
{
	BYTE *pBits = GetBits(0,0);
	if (pBits==NULL)
		return (-1);

	*pColor = RGB(pBits[2],pBits[1],pBits[0]);

	/*
	BYTE *pb = (BYTE *)pColor;
	pb[0] = pBits[0]; 
	pb[1] = pBits[1];
	pb[2] = pBits[2];
	pb[3] = 0;
	*/

//	*pColor = *((COLORREF *)pBits);

	//all is well
	return (0);
}

long DibSection::ReverseOrder( long COLOR )
{
	unsigned char * gun = (unsigned char *)(&COLOR);

	unsigned char t;

	t=gun[0];
	gun[0]=gun[2];
	gun[2]=t;

	return COLOR;
}

int DibSection::DrawGrid()
{
	BYTE *bits = (BYTE*)m_ds.dsBm.bmBits;
	int stride = ByteWidth();

	int height = Height();

	int step=10;
	for (int k=0; k<height; k+=step)
	{
		memset(bits,0,stride);
		bits+=(stride*step);
	}

	return (0);
}

int DibSection::IsVisiblePixel( int x, int y )
{
	BYTE* pBits = GetBits(y,x);

	int alpha = pBits[3];

	int visible = (alpha != 0);

	return (visible);
}

///////////////////////////////////////
//CBitmap functions
/////////////////////////////////////////

long	
CBitmapWidth(pCBitmap This)
{
	return ((DibSection*)This)->Width();
}

long
CBitmapHeight(pCBitmap This)
{
	return ((DibSection*)This)->Height();
}



pCBitmap
newCBitmapFromBMP(char * Filename)
{
	//We're going to force you to use the png's for now
	char FilenameCopy[32]; //To avoid side effects
	char* delimPtr;
	char delim = '.';

	//Avoid those pesky side effects
	strcpy(FilenameCopy,"images\\");
	strcat(FilenameCopy,Filename);

	//Change the bmp to png (so that we read the png file)
	delimPtr = strchr(FilenameCopy, delim);
	strcpy(delimPtr,".png");

	DibSection * pNewDibSection;

	pNewDibSection = new DibSection();

	pNewDibSection->Load(FilenameCopy);

	return pNewDibSection;
}

pCBitmap
newCBitmap(char * Name, uint32 Group)
{

	return newCBitmapFromBMP(Name);

}



pCBitmap
newCBitmapBlank(int32 Width, int32 Height)
{

	DibSection * pNewDibSection;


	pNewDibSection = new DibSection();

	pNewDibSection->Resize(32,Width,Height);

	return pNewDibSection;
}

pCBitmap
newCBitmapFrame(int32 Width, int32 Height, HDC BmpDC)
{
	return newCBitmapBlank(Width, Height);

//Hmmmm.. I'm not sure if I got this right. The old code is below.
//SHould I have used the DC?
/*
	pCBitmap This = (pCBitmap)malloc(sizeof(CBitmap));
	if (This && !CBitmapConstruct(This, Width, Height, (char *)0, BmpDC))
	{
		free(This);
		This = 0;
	}
	return This;
*/
 }

void		
deleteCBitmap(pCBitmap This)
{

	delete This;
}


void
CBitmapBitmapBltSection(pCBitmap This, int32 dx, int32 dy,
	int32 sx, int32 sy, int32 sw, int32 sh, pCBitmap Src)
{
	DibSection* dsThis = (DibSection*)This;

	if(Src != NULL) //Don't paint empty images
		dsThis->TransparentBlt(dsThis, dx, dy, sw,sh,(DibSection*)Src,sx,sy,sw,sh,BIGASSUINT /* nada */);
}

void
CBitmapTransparentBitmapBltSection(pCBitmap This, int32 dx, int32 dy,
	int32 sx, int32 sy, int32 sw, int32 sh, pCBitmap Src)
{
	DibSection* dsThis = (DibSection*)This;

	if(Src != NULL) //Don't paint empty images
		dsThis->TransparentBlt(dsThis, dx, dy, sw,sh,(DibSection*)Src,sx,sy,sw,sh,0 /* I guess? We should look at blast*/);
}

void
CBitmapBitmapBlt(pCBitmap This, int32 DestX, int32 DestY, pCBitmap Src)
{
	DibSection* dsThis = (DibSection*)This;

	if(Src != NULL) //Don't paint empty images
		dsThis->TransparentBlt(dsThis, DestX, DestY, ((DibSection*)Src)->Width(),((DibSection*)Src)->Height(),(DibSection*)Src,0,0, ((DibSection*)Src)->Width(),((DibSection*)Src)->Height(),BIGASSUINT);
}

void
CBitmapTransparentBitmapBlt(pCBitmap This, int32 DestX, int32 DestY, pCBitmap Src)
{
	DibSection* dsThis = (DibSection*)This;

	if(Src != NULL) //Don't paint empty images
		dsThis->TransparentBlt(dsThis, DestX, DestY, ((DibSection*)Src)->Width(),((DibSection*)Src)->Height(),(DibSection*)Src,0,0, ((DibSection*)Src)->Width(),((DibSection*)Src)->Height(),0);
}

void
CFrameAlphaTransparentBitmapBlt(pCBitmap This, int32 DestX, int32 DestY, pCBitmap Src) 
{
	DibSection* dsThis = (DibSection*)This;

	if(Src != NULL) //Don't paint empty images
		dsThis->AlphaBlt(dsThis, DestX, DestY, ((DibSection*)Src)->Width(),((DibSection*)Src)->Height(),(DibSection*)Src,0,0, ((DibSection*)Src)->Width(),((DibSection*)Src)->Height());
}


void	
CBitmapFillRect(pCBitmap This, int32 Left, int32 Top,
			int32 Right, int32 Bottom, uint8 Color)
{
	DibSection* dsThis = (DibSection*)This;
	COLORREF localColor = 0x00000000;
	RECT crect;
	crect.bottom = Bottom;
	crect.top = Top;
	crect.left = Left;
	crect.right = Right;

	if(Color == 99) //Bet View (next to chips)
		localColor = 0x00FF0000;

	if(Color == 34) //Win/Lose labels
		localColor = 0x00008800;

	dsThis->SolidFillRect(&crect, localColor);
}
void
CBitmapClear(pCBitmap This)
{
	DibSection* dsThis = (DibSection*)This;
	RECT crect;
	crect.bottom = dsThis->Height();
	crect.top = 0;
	crect.left = 0;
	crect.right = dsThis->Width();

	dsThis->SolidFillRect(&crect,0x00008800);
}

void	
CBitmapClearRect(pCBitmap This, int32 Left, int32 Top,
	int32 Right, int32 Bottom)
{
	DibSection* dsThis = (DibSection*)This;
	RECT crect;
	crect.bottom = Bottom;
	crect.top = Top;
	crect.left = Left;
	crect.right = Right;

	dsThis->SolidFillRect(&crect,0x00880000);
}

HBITMAP
CBitmapHBmp(pCBitmap This)
{
	return ((DibSection*)This)->m_hbmp;
}

uint8*
CBitmapBits(pCBitmap This)
{
	return ((DibSection*)This)->GetBitsAddress();
}

uint32
CBitmapRowBytes(pCBitmap This)
{
	uint32 result = 0;
	DibSection * dsThis = (DibSection*) This;

	result = (dsThis->Width()) * 4;

	return result;
}

HBITMAP
CBitmapMonoMask(pCBitmap This)
{
	DibSection * dsThis = (DibSection*) This;
	void * dsNew;

	dsNew = newCBitmapBlank(dsThis->Width(),dsThis->Height());

	return ((DibSection*)dsNew)->m_hbmp;


//Hmmm... Another scary one... How about Just a blank one of the same size?
/* Old imp below

	HBITMAP hmask;

	BmpMonoHeader.Header.biWidth = CBitmapWidth(dsThis);
	BmpMonoHeader.Header.biHeight = CBitmapHeight(This);

	hmask = CreateBitmap(CBitmapWidth(This), CBitmapHeight(This), 1, 1, NULL);
	
	SetDIBits(CFrameDC(CScreenGetFrame(gScreen)), hmask, 0,
		CBitmapHeight(This), CBitmapBits(This),
		(BITMAPINFO*)&BmpMonoHeader, DIB_RGB_COLORS);

	return hmask;
*/
}





#endif	//USE32BITDIB
